package Client;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dialog.ModalityType;
import java.awt.Font;
import java.awt.GraphicsEnvironment;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.IOException;

import javax.swing.JDialog;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;

import Client.excepciones.IncorrectCodeException;
import Client.excepciones.UnexpectedErrorException;

/**
 * Clase MenuBar para la aplicacion cliente.
 * @author inlacou
 *
 */
public class JMenuBarCliente extends JMenuBar {

	private JFrameCliente jf;

	private JMenu file;
	private JMenuItem connect;
	private JMenuItem exit;

	private JMenu options;

	private JMenu lf;
	private JRadioButtonMenuItem[] LaFs;
	private LookAndFeelInfo[] LaFi;
	private ActionListener LaFsAL;

	private JMenu letra;
	private JMenu tiposLetra;
	private Font[] fonts;
	private JRadioButtonMenuItem[] letras;
	@SuppressWarnings("unused") private MenuScroller MStipos;
	private ActionListener fontTypeAL;
	private JMenu lcolor;
	private JRadioButtonMenuItem[] JRBMIlcolores;
	private Color[] colores;
	private ActionListener fontlColAL;
	private JMenu tamanyo;
	private JRadioButtonMenuItem[] tamanyos;
	private ActionListener fontTamAL;
	private int maxTamLetra;
	private JMenu fondo;
	private JRadioButtonMenuItem[] JRBMIfcolores;
	private ActionListener backColAL;

	private JMenu help;
	private JMenuItem general_help;
	private JMenuItem about;

	private Color backgroundColor;
	private Color fontColor;

	/**
	 * Constructor de la clase JMenuBarCliente, que obtiene su JFramePadre.
	 * @param contenedor
	 */
	public JMenuBarCliente(JFrameCliente contenedor){

		//Inicializacion de variables.
		jf = contenedor;
		maxTamLetra = 21;
		file = new JMenu("File");
		file.setMnemonic(KeyEvent.VK_F);
		connect = new JMenuItem("Connect");
		exit = new JMenuItem("Exit", KeyEvent.VK_E);
		options = new JMenu("Options");
		options.setMnemonic(KeyEvent.VK_O);
		lf = new JMenu("Look&Feel");
		//XXX instalarLaFs();
		LaFi = UIManager.getInstalledLookAndFeels();
		LaFs = new JRadioButtonMenuItem[LaFi.length];
		letra = new JMenu("Letra");
		tiposLetra = new JMenu("Tipo");
		MStipos = new MenuScroller(tiposLetra, 15, 100);
		tamanyo = new JMenu("Tamanyo");
		tamanyos = new JRadioButtonMenuItem[maxTamLetra-9]; 
		lcolor = new JMenu("Color");
		fondo = new JMenu("Fondo");
		colores = new Color[]{	Color.BLACK, Color.DARK_GRAY, Color.GRAY, Color.LIGHT_GRAY,
				Color.RED, Color.MAGENTA, Color.BLUE, Color.CYAN, Color.GREEN, Color.ORANGE,
				Color.YELLOW, Color.WHITE};
		JRBMIlcolores = new JRadioButtonMenuItem[colores.length];
		JRBMIfcolores = new JRadioButtonMenuItem[colores.length];

		help = new JMenu("Help");
		help.setMnemonic(KeyEvent.VK_H);
		general_help = new JMenuItem("General Help", KeyEvent.VK_G);
		general_help.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_H,
				java.awt.Event.CTRL_MASK));
		about = new JMenuItem("About...", KeyEvent.VK_A);
		about.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_A,
				java.awt.Event.CTRL_MASK));

		backgroundColor = this.getBackground();
		fontColor = this.getForeground();

		//Barra de Menu.
		//File
		file.add(connect);
		file.addSeparator();
		file.add(exit);
		this.add(file);

		//Options
		options.add(lf);
		addLaFRBMenuItem(lf, LaFi, LaFs);
		options.add(letra);
		letra.add(tiposLetra);
		addFontTypeRBMenuItem(tiposLetra);
		letra.add(tamanyo);
		addFontTamRBMenuItem(tamanyo);
		letra.add(lcolor);
		addFontColorRBMenuItem(lcolor);
		options.add(fondo);
		addBackColorRBMenuItem(fondo);
		this.add(options);

		//Help
		help.add(general_help);
		help.addSeparator();
		help.add(about);
		this.add(help);

		addShortcuts(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_C,
				java.awt.Event.CTRL_MASK),
				KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_E,
						java.awt.Event.CTRL_MASK));

		connect.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				if(connect.getText().equals("Connect")){
					jf.setMensaje("");
					jf.conectar();
				}else{
					try {
						jf.cerrarConexion();
					} catch (IOException e1) {
						JOptionPane.showMessageDialog(jf, "Fallo en la desconexion con el servidor.");
					} catch (IncorrectCodeException e2) {
						JOptionPane.showMessageDialog(jf, "Respuesta inesperada del servidor.");
					} catch (UnexpectedErrorException e3) {
						JOptionPane.showMessageDialog(jf, "Error inesperado. Lo sentimos.");
					}
					jf.desconectar();
				}
			}
		});

		exit.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				try {
					if(jf.cerrarConexion()){
						System.exit(0);
					}
				} catch (IOException e1) {
					JOptionPane.showMessageDialog(jf, "Fallo en la desconexion con el servidor.");
				} catch (IncorrectCodeException e2) {
					JOptionPane.showMessageDialog(jf, "Respuesta inesperada del servidor.");
				} catch (UnexpectedErrorException e3) {
					JOptionPane.showMessageDialog(jf, "Error inesperado. Lo sentimos.");
				}
			}
		});

		general_help.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				JDialogAyudaGeneral jdAG = new JDialogAyudaGeneral(jf, "General Help", ModalityType.DOCUMENT_MODAL);
				jdAG.setVisible(true);
			}
		});

		about.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				JDialogAcercaDe jdAD = new JDialogAcercaDe(jf, "About...", ModalityType.DOCUMENT_MODAL);
				jdAD.setVisible(true);
			}
		});



		//Propiedades.
		actualizarLaFs("Metal");
		actualizarTamanyosLetra("13");
		actualizarTypeLetra("Dialog.plain");
	}

	/**
	 * Metodo que a�ade al JMenu pasado por parametro los RadioButtonMenuItem de tipos de letra creados en ejecucion. 
	 * Tambien define el actionListener que les correspone y se lo a�ade.
	 * @param jm
	 * @param aSource
	 * @param aJRBMI
	 */
	private void addLaFRBMenuItem(JMenu jm, LookAndFeelInfo[] aSource, JRadioButtonMenuItem[] aJRBMI){
		LaFsAL = new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				actualizarLaFs(((JRadioButtonMenuItem) e.getSource()).getText());
				setLF(((JRadioButtonMenuItem) e.getSource()).getText());
			}
		};
		for(int i = 0; i < aSource.length; i++){
			aJRBMI[i] = new JRadioButtonMenuItem(aSource[i].getName());
			aJRBMI[i].addActionListener(LaFsAL);
			jm.add(aJRBMI[i]);
		}
	}

	/**
	 * Metodo que actualiza los radioButtons de los Look&Feel de modo que solo quede pulsado el que tenga como nombre lo que se pasa por parametro.
	 * @param s
	 */
	private void actualizarLaFs(String s){
		for(int i = 0; i < LaFs.length; i++){
			if(LaFs[i].getText().equals(s)){
				LaFs[i].setEnabled(false);
				LaFs[i].setSelected(true);
			}else{
				LaFs[i].setSelected(false);
				LaFs[i].setEnabled(true);
			}
		}
	}

	/**
	 * Metodo que cambia el Look&Feel actual por el de nombre igual al pasado como parametro.
	 * @param name
	 */
	private void setLF(String name){
		for(UIManager.LookAndFeelInfo laf:UIManager.getInstalledLookAndFeels()){
			if(name.equals(laf.getName()))
				try {
					UIManager.setLookAndFeel(laf.getClassName());
				} catch (Exception ex) {
					ex.printStackTrace();
				}
		}
		SwingUtilities.updateComponentTreeUI(jf);
		jf.repaint();
	}

	/**
	 * Metodo que a�ade al JMenu pasado por parametro los RadioButtonMenuItem de tipos de letra creados en ejecucion. 
	 * Tambien define el actionListener que les correspone y se lo a�ade.
	 * @param jm
	 */
	private void addFontTypeRBMenuItem(JMenu jm){
		fonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
		letras = new JRadioButtonMenuItem[fonts.length];
		fontTypeAL = new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				actualizarTypeLetra(((JRadioButtonMenuItem) e.getSource()).getText());
				setTypeLetra(((JRadioButtonMenuItem) e.getSource()).getText());
			}
		};
		for(int i = 0; i < fonts.length; i++){
			letras[i] = new JRadioButtonMenuItem(fonts[i].getName());
			letras[i].addActionListener(fontTypeAL);
			jm.add(letras[i]);
		}
	}

	/**
	 * Metodo que actualiza los RadioButtonMenuItem de tipos de letra,
	 * de modo que quede marcado solo el que se pasa como parametro.
	 * @param s
	 */
	private void actualizarTypeLetra(String s){
		for(int i = 0; i < fonts.length; i++){
			if(letras[i].getText().equals(s)){
				letras[i].setEnabled(false);
				letras[i].setSelected(true);
			}else{
				letras[i].setSelected(false);
				letras[i].setEnabled(true);
			}
		}
	}

	/**
	 * Metodo que cambia el tipo de letra al pasado por parametro.
	 * @param name
	 */
	private void setTypeLetra(String name){
		for(Font f: fonts){
			if(name.equals(f.getName())){
				try {
					f = f.deriveFont(this.getFont().getSize2D());
					this.setFont(f);
				} catch (Exception ex) {
					ex.printStackTrace();
				}
			}
		}
		jf.repaint();
	}

	/**
	 * Metodo que a�ade al JMenu pasado por parametro los RadioButtonMenuItem de colores de letra creados en ejecucion. 
	 * Tambien define el actionListener que les correspone y se lo a�ade. 
	 * @param jm
	 */
	private void addFontColorRBMenuItem(JMenu jm){
		fontlColAL = new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				actualizarColorLetra(((JRadioButtonMenuItem) e.getSource()));
				setColorLetra(((JRadioButtonMenuItem) e.getSource()));
			}
		};
		for(int i = 0; i < colores.length; i++){
			JRadioButtonMenuItem jrbmi = new JRadioButtonMenuItem();
			jrbmi.setBackground(colores[i]);
			jrbmi.addActionListener(fontlColAL);
			JRBMIlcolores[i] = jrbmi;
			jm.add(jrbmi);
		}
	}

	/**
	 * Metodo que actualiza los RadioButtonMenuItem de colores de letra,
	 * de modo que quede marcado solo el que se pasa como parametro.
	 * @param JRBMI
	 */
	private void actualizarColorLetra(JRadioButtonMenuItem JRBMI){
		for(int i = 0; i < JRBMIlcolores.length; i++){
			if(JRBMI.getBackground().equals(JRBMIlcolores[i].getBackground())){
				JRBMIlcolores[i].setEnabled(false);
				JRBMIlcolores[i].setSelected(true);
			}else{
				JRBMIlcolores[i].setSelected(false);
				JRBMIlcolores[i].setEnabled(true);
			}
		}
	}

	/**
	 * Metodo que cambia el color de letra al pasado por parametro.
	 * @param JRBMI
	 */
	private void setColorLetra(JRadioButtonMenuItem JRBMI){
		fontColor = JRBMI.getBackground();
		jf.repaint();
	}

	/**
	 * Metodo que a�ade al JMenu pasado por parametro los RadioButtonMenuItem de colores de fondo creados en ejecucion. 
	 * Tambien define el actionListener que les correspone y se lo a�ade. 
	 * @param jm
	 */
	private void addBackColorRBMenuItem(JMenu jm){
		backColAL = new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				actualizarColorFondo(((JRadioButtonMenuItem) e.getSource()));
				setColorFondo(((JRadioButtonMenuItem) e.getSource()));
			}
		};
		for(int i = 0; i < colores.length; i++){
			JRadioButtonMenuItem jrbmi = new JRadioButtonMenuItem();
			jrbmi.setBackground(colores[i]);
			jrbmi.addActionListener(backColAL);
			JRBMIfcolores[i] = jrbmi;
			jm.add(jrbmi);
		}
	}

	/**
	 * Metodo que actualiza los RadioButtonMenuItem de color de fondo,
	 * de modo que quede marcado solo el que se pasa como parametro.
	 * @param JRBMI
	 */
	private void actualizarColorFondo(JRadioButtonMenuItem JRBMI){
		for(int i = 0; i < JRBMIfcolores.length; i++){
			if(JRBMI.getBackground().equals(JRBMIfcolores[i].getBackground())){
				JRBMIfcolores[i].setEnabled(false);
				JRBMIfcolores[i].setSelected(true);
			}else{
				JRBMIfcolores[i].setSelected(false);
				JRBMIfcolores[i].setEnabled(true);
			}
		}
	}

	/**
	 * Metodo que cambia el color de fondo al pasado por parametro.
	 * @param JRBMI
	 */
	private void setColorFondo(JRadioButtonMenuItem JRBMI){
		backgroundColor = JRBMI.getBackground();
		jf.repaint();
		SwingUtilities.updateComponentTreeUI(jf);
	}

	/**
	 * Metodo que a�ade al JMenu pasado por parametro los RadioButtonMenuItem de tama�os de letra creados en ejecucion. 
	 * Tambien define el actionListener que les correspone y se lo a�ade. 
	 * @param jm
	 */
	private void addFontTamRBMenuItem(JMenu jm){
		fontTamAL = new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				actualizarTamanyosLetra(((JRadioButtonMenuItem) e.getSource()).getName());
				setTamanyosLetra(((JRadioButtonMenuItem) e.getSource()).getName());
			}
		};
		for(int i = 0, a = 9; a < maxTamLetra; i++, a++){
			JRadioButtonMenuItem jrbmi = new JRadioButtonMenuItem(a + " pt");
			jrbmi.setName(String.valueOf(a));
			jrbmi.addActionListener(fontTamAL);
			tamanyos[i] = jrbmi;
			jm.add(jrbmi);
		}
	}

	/**
	 * Metodo que actualiza los RadioButtonMenuItem de tama�o de letra,
	 * de modo que quede marcado solo el que se pasa como parametro.
	 * @param s
	 */
	private void actualizarTamanyosLetra(String s){
		for(int i = 0; i < tamanyos.length; i++){
			if(s.equals(tamanyos[i].getName().trim())){
				tamanyos[i].setEnabled(false);
				tamanyos[i].setSelected(true);
			}else{
				tamanyos[i].setSelected(false);
				tamanyos[i].setEnabled(true);
			}
		}
	}

	/**
	 * Metodo que cambia el tama�o de letra al pasado por parametro.
	 * @param s
	 */
	private void setTamanyosLetra(String s){
		Font f = this.getFont();
		f = f.deriveFont(Float.parseFloat(s));
		this.setFont(f);
		jf.repaint();
	}

	/**
	 * Metodo que actualiza la fuente, el color de letra y el fondo del componente introducido por parametro.
	 * @param c
	 */
	public void actualizar(Component c){
		c.setFont(this.getFont());
		c.setForeground(fontColor);
		c.setBackground(backgroundColor);
	}

	/**
	 * Metodo que cambia el texto del MenuItem "connect" a "Connect".
	 */
	protected void connect(){
		connect.setText("Connect");
	}

	/**
	 * Metodo que cambia el texto del MenuItem "connect" a "Disconnect".
	 */
	protected void disconnect(){
		connect.setText("Disconnect");
	}

	/**
	 * Metodo para anyadir los shortcuts pertinentes.
	 * @param connectKS
	 * @param exitKS
	 */
	public void addShortcuts(KeyStroke connectKS, KeyStroke exitKS){
		connect.setAccelerator(connectKS);
		exit.setAccelerator(exitKS);

	}
}
